from fsm import FSM
from eventServer import eventServer
from vec3 import Vec3
from keys import keys
from gameServer import gameServer

import math

from OpenGL.GLU import *

class Camera(FSM):
    def __init__(self):
        FSM.__init__(self)
        
        self.defaultVar("pos",Vec3(10,10,10))
        self.defaultVar("lookAt",Vec3(0,0,0))
        self.defaultVar("up",Vec3(0,1,0))
        self.defaultVar("states",['follower','cylinder','free','firstPerson'])
        self.defaultVar("stateKey","c")
        self.setVar("statePos",0)
        
        eventServer.register("update",self.update)
        eventServer.register("cameraRender",self.render)
        #eventServer.register("keyDown",self.keyDown)
        #eventServer.register("keyUp",self.keyUp)
        
        self.setState(self.getVar("states")[0])
        
    def update(self, cmd, args):
        self.dispatch("update",args)
        
    def render(self, cmd, args):
        if not self.dispatch("render",args):
            pos = self.getVar("pos")
            lookAt = self.getVar("lookAt")
            up = self.getVar("up")
            gluLookAt(pos.x,pos.y,pos.z,lookAt.x,lookAt.y,lookAt.z,up.x,up.y,up.z)

    def keyDown(self, cmd, args):
        if args['key'] == keys[self.getVar("stateKey")]:
            states = self.getVar("states")
            statePos = (self.getVar("statePos")+1) % len(states)
            self.setVar("statePos",statePos)
            state = states[statePos]
            print "switching to camera state %s" % state
            self.setState(state)
        else:
            self.dispatch("keyDown",args)
        
    def keyUp(self, cmd, args):
        self.dispatch("keyUp",args)
        
    #cylinder mode
        
    def startState_cylinder(self, cmd, args):
        self.setVar("yaw",math.pi/2)
        self.defaultVar("dyaw",0)
        self.defaultVar("yawSpeed",1.0)
        self.defaultVar("yawLeftKey","left")
        self.defaultVar("yawRightKey","right")
        
        self.defaultVar("h",0)
        self.defaultVar("dh",0)
        self.defaultVar("hSpeed",10.0)
        self.defaultVar("hUpKey","up")
        self.defaultVar("hDownKey","down")
        
        self.defaultVar("dist",10)
        self.defaultVar("ddist",0)
        self.defaultVar("distSpeed",10.0)
        self.defaultVar("distInKey","pgup")
        self.defaultVar("distOutKey","pgdn")
        
        self.defaultVar("lookAt",Vec3(0,0,0))
        
    def update_cylinder(self, cmd, args):
        dtime = args["dtime"]
        
        yaw = self.getVar("yaw") + self.getVar("dyaw") * dtime
        self.setVar("yaw",yaw)
        
        h = self.getVar("h") + self.getVar("dh") * dtime
        self.setVar("h",h)
        
        dist = self.getVar("dist") + self.getVar("ddist") * dtime
        self.setVar("dist",dist)
        
        lookAt = self.getVar("lookAt")
        newPos = Vec3(dist * math.cos(yaw),h,dist * math.sin(yaw))
        
        self.setVar("pos",lookAt + newPos)
        
    def keyDown_cylinder(self, cmd, args):
        key = args["key"]
        
        if key == keys[self.getVar("yawLeftKey")]:
            self.setVar("dyaw",self.getVar("dyaw") + self.getVar("yawSpeed"))
        elif key == keys[self.getVar("yawRightKey")]:
            self.setVar("dyaw",self.getVar("dyaw") - self.getVar("yawSpeed"))
            
        elif key == keys[self.getVar("hUpKey")]:
            self.setVar("dh",self.getVar("dh") + self.getVar("hSpeed"))
        elif key == keys[self.getVar("hDownKey")]:
            self.setVar("dh",self.getVar("dh") - self.getVar("hSpeed"))
            
        elif key == keys[self.getVar("distInKey")]:
            self.setVar("ddist",self.getVar("ddist") - self.getVar("distSpeed"))
        elif key == keys[self.getVar("distOutKey")]:
            self.setVar("ddist",self.getVar("ddist") + self.getVar("distSpeed"))
            
    def keyUp_cylinder(self, cmd, args):
        key = args["key"]
        
        if key == keys[self.getVar("yawLeftKey")]:
            self.setVar("dyaw",self.getVar("dyaw") - self.getVar("yawSpeed"))
        elif key == keys[self.getVar("yawRightKey")]:
            self.setVar("dyaw",self.getVar("dyaw") + self.getVar("yawSpeed"))
            
        elif key == keys[self.getVar("hUpKey")]:
            self.setVar("dh",self.getVar("dh") - self.getVar("hSpeed"))
        elif key == keys[self.getVar("hDownKey")]:
            self.setVar("dh",self.getVar("dh") + self.getVar("hSpeed"))
            
        elif key == keys[self.getVar("distInKey")]:
            self.setVar("ddist",self.getVar("ddist") + self.getVar("distSpeed"))
        elif key == keys[self.getVar("distOutKey")]:
            self.setVar("ddist",self.getVar("ddist") - self.getVar("distSpeed"))
            
    #free mode
    
    def startState_free(self, cmd, args):
        pos = self.getVar("pos")
        lookAt = self.getVar("lookAt")
        diff = lookAt - pos
        yaw = math.atan2(diff.x,diff.z)
        
        #dist = math.sqrt(diff.x * diff.x + diff.z * diff.z)
        #pitch = math.atan2(dist,diff.y)
        pitch = 0
        
        self.defaultVar("yaw",yaw)
        self.defaultVar("pitch",pitch)
        
        self.defaultVar("dyaw",0)
        self.defaultVar("dpitch",0)
        self.defaultVar("forwardSpeed",0)
        self.defaultVar("rightSpeed",0)
        self.defaultVar("upSpeed",0)
        
        self.defaultVar("moveSpeed",5.0)
        self.defaultVar("turnSpeed",0.5)
        
        self.defaultVar("yawLeftKey","left")
        self.defaultVar("yawRightKey","right")
        self.defaultVar("pitchUpKey","up")
        self.defaultVar("pitchDownKey","down")
        self.defaultVar("moveForwardKey","w")
        self.defaultVar("moveBackKey","s")
        self.defaultVar("moveLeftKey","a")
        self.defaultVar("moveRightKey","d")
        self.defaultVar("moveUpKey","r")
        self.defaultVar("moveDownKey","f")
        
    def update_free(self, cmd, args):
        dtime = args['dtime']
        
        yaw = self.getVar("yaw") + self.getVar("dyaw") * dtime
        self.setVar("yaw",yaw)
        
        pitch = self.getVar("pitch") + self.getVar("dpitch") * dtime
        self.setVar("pitch",pitch)
        
        yaw += math.pi
        forward = Vec3(math.cos(yaw) * math.cos(pitch), math.sin(pitch), math.sin(yaw) * math.cos(pitch))
        right = Vec3(math.cos(yaw+math.pi/2),0,math.sin(yaw+math.pi/2))
        up = right.cross(forward)
        
        velForward = forward * self.getVar("forwardSpeed")
        velRight = right * self.getVar("rightSpeed")
        velUp = up * self.getVar("upSpeed")
        
        self.setVar("pos",self.getVar("pos") + (velForward + velRight + velUp) * dtime)
        self.setVar("lookAt",self.getVar("pos") + forward)
        
    def keyDown_free(self, cmd, args):
        key = args['key']
        
        if key == keys[self.getVar("yawLeftKey")]:
            self.setVar("dyaw",self.getVar("dyaw") - self.getVar("turnSpeed"))
        elif key == keys[self.getVar("yawRightKey")]:
            self.setVar("dyaw",self.getVar("dyaw") + self.getVar("turnSpeed"))

        elif key == keys[self.getVar("pitchUpKey")]:
            self.setVar("dpitch",self.getVar("dpitch") + self.getVar("turnSpeed"))
        elif key == keys[self.getVar("pitchDownKey")]:
            self.setVar("dpitch",self.getVar("dpitch") - self.getVar("turnSpeed"))

        elif key == keys[self.getVar("moveForwardKey")]:
            self.setVar("forwardSpeed",self.getVar("forwardSpeed") + self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveBackKey")]:
            self.setVar("forwardSpeed",self.getVar("forwardSpeed") - self.getVar("moveSpeed"))

        elif key == keys[self.getVar("moveLeftKey")]:
            self.setVar("rightSpeed",self.getVar("rightSpeed") - self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveRightKey")]:
            self.setVar("rightSpeed",self.getVar("rightSpeed") + self.getVar("moveSpeed"))
            
        elif key == keys[self.getVar("moveUpKey")]:
            self.setVar("upSpeed",self.getVar("upSpeed") + self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveDownKey")]:
            self.setVar("upSpeed",self.getVar("upSpeed") - self.getVar("moveSpeed"))

    def keyUp_free(self, cmd, args):
        key = args['key']
        
        if key == keys[self.getVar("yawLeftKey")]:
            self.setVar("dyaw",self.getVar("dyaw") + self.getVar("turnSpeed"))
        elif key == keys[self.getVar("yawRightKey")]:
            self.setVar("dyaw",self.getVar("dyaw") - self.getVar("turnSpeed"))

        elif key == keys[self.getVar("pitchUpKey")]:
            self.setVar("dpitch",self.getVar("dpitch") - self.getVar("turnSpeed"))
        elif key == keys[self.getVar("pitchDownKey")]:
            self.setVar("dpitch",self.getVar("dpitch") + self.getVar("turnSpeed"))

        elif key == keys[self.getVar("moveForwardKey")]:
            self.setVar("forwardSpeed",self.getVar("forwardSpeed") - self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveBackKey")]:
            self.setVar("forwardSpeed",self.getVar("forwardSpeed") + self.getVar("moveSpeed"))

        elif key == keys[self.getVar("moveLeftKey")]:
            self.setVar("rightSpeed",self.getVar("rightSpeed") + self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveRightKey")]:
            self.setVar("rightSpeed",self.getVar("rightSpeed") - self.getVar("moveSpeed"))

        elif key == keys[self.getVar("moveUpKey")]:
            self.setVar("upSpeed",self.getVar("upSpeed") - self.getVar("moveSpeed"))
        elif key == keys[self.getVar("moveDownKey")]:
            self.setVar("upSpeed",self.getVar("upSpeed") + self.getVar("moveSpeed"))
            
    #first person
    
    def startState_firstPerson(self, cmd, args):
        self.defaultVar("firstPersonPlayer",0)
        
    def update_firstPerson(self, cmd, args):
        playerName = 'player%d' % self.getVar('firstPersonPlayer')
        player = gameServer.getObject(playerName)
        if player:
            if player.getVar("face") == 'right':
                dx = 1
            else:
                dx = -1
            pos = player.getVar("pos")
            self.setVar("pos",Vec3(pos.x,pos.y,pos.z+abs(dx)))
            self.setVar("lookAt",Vec3(pos.x+dx,pos.y,pos.z+abs(dx)))

    #follower
    
    def startState_follower(self, cmd, args):
        print "startState follower"
        self.defaultVar("numPlayers",1)
        self.defaultVar("minDist",20)
        self.defaultVar("followTime",0.25)
        
    def update_follower(self, cmd, args):
        minx = maxx = miny = maxy = None
        anyFound = False
        for i in range(self.getVar("numPlayers")):
            playerName = 'player%d' % i
            player = gameServer.getObject(playerName)
            if player and not player.getVar("dead"):
                anyFound = True
                pos = player.getVar("pos")
                if not minx or pos.x < minx:
                    minx = pos.x
                if not maxx or pos.x > maxx:
                    maxx = pos.x
                if not miny or pos.y < miny:
                    miny = pos.y
                if not maxy or pos.y > maxy:
                    maxy = pos.y
                    
        level = gameServer.getObject("level")
        if level:
            for player, (time, pos) in level.spawnPlayers.iteritems():
                anyFound = True
                if not minx or pos.x < minx:
                    minx = pos.x
                if not maxx or pos.x > maxx:
                    maxx = pos.x
                if not miny or pos.y < miny:
                    miny = pos.y
                if not maxy or pos.y > maxy:
                    maxy = pos.y
                    
        if anyFound:
            x = (minx + maxx) / 2.0
            y = (miny + maxy) / 2.0
            w = maxx - minx
            h = maxy - miny
            minDist = self.getVar("minDist")
            
            destPos = Vec3(x,y,max(max(w,h)*1.5,minDist))
            pos = self.getVar("pos")
            
            timeGain = args['dtime'] / self.getVar("followTime")
            if w > minDist:
                distGain = minDist / w
            else:
                distGain = 1
            
            newPos = pos + (destPos - pos) * timeGain * distGain
            #newPos = (destPos + pos) / 2.0
            
            self.setVar("pos",newPos)
            self.setVar("lookAt",newPos * Vec3(1,1,0))
